package org.zjt.mock.demo.mock.config;

import com.alibaba.ttl.TtlRunnable;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.MethodParameter;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.validation.*;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.*;
import org.zjt.mock.demo.mock.annotation.RequestParam2;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Description:
 *
 * @author juntao.zhang
 * Date: 2018-06-21 下午1:52
 * @see
 */


@Configuration
@Slf4j
public class CustomizedMvcConfigurer extends WebMvcConfigurerAdapter {


    /**
     * 异常信息处理类
     * @param exceptionResolvers
     */
    @Override
    public  void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers){
        exceptionResolvers.add(0, (httpServletRequest, httpServletResponse, o, e) -> {
            ExceptionHandleStrategies exceptionHandleStrategies = exceptionHandleStrategies();
            exceptionHandleStrategies.generateHandler(() -> exceptionHandleStrategies.handle(e)).accept(httpServletResponse);
            ModelAndView modelAndView = new ModelAndView();
            return modelAndView;
        });
    }


    /**
     * 请求当绑定数据异常时候。
     * @see WebMvcConfigurationSupport#getConfigurableWebBindingInitializer()
     * @return
     */
    @Override
    @Primary
    public MessageCodesResolver getMessageCodesResolver(){
        return new DefaultMessageCodesResolver();
    }


    @Override
    @Primary
    public Validator getValidator(){
        return new UserValidator();
    }


    @Bean
    public ExceptionHandleStrategies exceptionHandleStrategies(){
        return new ExceptionHandleStrategies();
    }


    /**
     * 请求路径匹配器
     * @param configurer
     */
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer){
        configurer.setPathMatcher(new CustomizedAntPathMatcher());
    }


    /**
     * 设置默认的 Response content Type
     * @param configurer
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer){
        configurer.defaultContentType(MediaType.TEXT_HTML);
        configurer.defaultContentTypeStrategy(new CustomizedContentNegotiationStrategy());
    }


    /**
     * 字符集编码设置
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(0);
        filterRegistrationBean.setFilter(new EncodingFilter());
        return filterRegistrationBean;
    }


    /**
     * 配置异步http请求配置（异步servlet）
     * Configure asynchronous request handling options.
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer){

        /** 异步 servlet 线程的池**/
        SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
        simpleAsyncTaskExecutor.setThreadNamePrefix("async-request-executor");
        simpleAsyncTaskExecutor.setConcurrencyLimit(1000);

        //线程装饰器   用于异步的servlet ThreadLocal内容传递
        simpleAsyncTaskExecutor.setTaskDecorator(runnable -> TtlRunnable.get(runnable));


        configurer.setDefaultTimeout(100);
        configurer.setTaskExecutor(simpleAsyncTaskExecutor);


        //异步servlet请求回调时间处理
        configurer.registerCallableInterceptors(new AsyncRequestCallableEventProcessor());
        configurer.registerDeferredResultInterceptors(new  AsyncRequestDeferredResultEventProcessor());
    }


    /**
     * servlet 容器对静态资源的处理配置
     * @param configurer
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
        configurer.enable();
    }


    /**
     *
     * Formatter 在 ArgumentResolvers 之前反序列化
     *
     * Converter 在 ArgumentResolvers 之前反序列化
     *
     * controller 参数的格式化，可以使用对参数类型转换
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry){
        registry.addFormatter(new LocalDateTimeFormatter());
        registry.addConverter(new LocalDateTimeConverter());
    }

    /**
     * 根据 controller 参数的注解，绑定html数据到参数上
     * @param argumentResolvers
     * @see RequestParam2
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers){
        argumentResolvers.add(0,customizedHandlerMethodArgumentResolver());
    }

    /**
     * {@link RequestParam2} 标记的参数 处理器
     * @return
     */
    @Bean
    public CustomizedHandlerMethodArgumentResolver customizedHandlerMethodArgumentResolver() {
        return new CustomizedHandlerMethodArgumentResolver();
    }

    /**
     * controller 返回值的处理（异步、非异步）
     * @param returnValueHandlers
     */
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers){
        returnValueHandlers.add(new CustomizedAsyncHandlerMethodReturnValueHandler());
    }


    /**
     * 装配自定义序列化器
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters){
        converters.add(customizedJackson2HttpMessageConverter());
    }


    /**
     * 自定义controller返回对象的序列化
     * @return
     */
    @Bean
    public CustomizedJackson2HttpMessageConverter customizedJackson2HttpMessageConverter() {
        CustomizedJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new CustomizedJackson2HttpMessageConverter();
        //设置中文编码格式
        List<MediaType> mediaTypes = Arrays.asList(MediaType.APPLICATION_JSON_UTF8, MediaType.APPLICATION_JSON);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(mediaTypes);
        return mappingJackson2HttpMessageConverter;
    }

    /**
     * 自定义序列化器
     * @return
     */
    /*@Bean
    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        //设置日期格式
        ObjectMapper objectMapper = new ObjectMapper();

        SimpleModule module = new SimpleModule();

        module.addDeserializer(LocalDateTime.class, new CustomizedDeSerializer.LocalDateTimeDeSerializer());
        module.addSerializer(LocalDateTime.class, new CustomizedSerializer.LocalDateTimeSerializer());
        objectMapper.registerModule(module);
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);

        //设置中文编码格式
        List<MediaType> mediaTypes = Arrays.asList(MediaType.APPLICATION_JSON_UTF8, MediaType.APPLICATION_JSON);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(mediaTypes);
        return mappingJackson2HttpMessageConverter;
    }
*/
}
